﻿// -----------------------------------------------------------------------
// <copyright file="Operations.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace ImageP
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;   
    using System.Linq;
    using System.Text;  
  
    /// <summary>
    /// Operation can be made on image like arithmetic operations,logic operations ,AND ,OR operations and Matching
    /// </summary>
   public class Operations
    {
        /// <summary>
        /// Image Global Height
        /// </summary>
      private int height = 0;

        /// <summary>
        /// Image Global Width
        /// </summary>
       private int width = 0;

        /// <summary>
        /// Global Buffer
        /// </summary>
     private RGBcolor[,] buffer;

       /// <summary>
       /// Object from class Read Image
       /// </summary>
        private ReadImage finalBuffer = new ReadImage();
        
        /// <summary>
        /// Object from class Normalize
        /// </summary>
       private Normalize normalizing = new Normalize();

        /// <summary>
        /// applying the quantization method by reducing bits per pixel.
        /// </summary>
        /// <param name="mask">input mask</param>
        /// <param name="filepath">file path</param>
        /// <returns>Bitmap image</returns>  
        public Bitmap Quantization(int mask, string filepath)
        {
            Bitmap m = new Bitmap(filepath);
            Bitmap m1 = new Bitmap(m.Width, m.Height);
            int pixelColor;
            int r1, r2, r3;
            int r, g, b;
            byte maskFinal = (255 << 5) & 0xFF;

            for (int i = 0; i < m.Height; i++)
            {
                for (int j = 0; j < m.Width; j++)
                {
                    pixelColor = m.GetPixel(j, i).ToArgb();
                    r = Color.FromArgb(pixelColor).R;
                    r1 = r & maskFinal;

                    g = Color.FromArgb(pixelColor).G;
                    r2 = g & maskFinal;

                    b = Color.FromArgb(pixelColor).B;
                    r3 = b & maskFinal;
                    m1.SetPixel(j, i, System.Drawing.Color.FromArgb(255, Convert.ToInt32(r1), Convert.ToInt32(r2), Convert.ToInt32(r3)));
                }
            }

            return m1;
        }

       /// <summary>
        /// applying the histogram matching ,by mathching each color in the first image with the nearest in the second image 
       /// </summary>
       /// <param name="image1">Source Image of type ReadImage </param>
       /// <param name="image2">Destination Image of type ReadImage</param>
       /// <returns>2D buffer of new matched image </returns>
        public RGBcolor[,] HistogramMatching(ReadImage image1, ReadImage image2)
        {
            Enhancements source = new Enhancements();
            Enhancements destination = new Enhancements();
            this.buffer = new RGBcolor[image1.ImageHeight, image1.ImageWidth];
            source.Equalize(image1.Buffer, image1.ImageWidth, image1.ImageHeight);
            destination.Equalize(image2.Buffer, image2.ImageWidth, image2.ImageHeight);
            int[] matchedRedArr = new int[256];
            int[] matchedGreenArr = new int[256];
            int[] matchedBlueArr = new int[256];
            int matchRed = 0;
            int matchGreen = 0;
            int matchBlue = 0; ////final matched value to be added to array 
            int calculation = 0;
            int sredValue = 0, sgreenValue = 0, sblueValue = 0;
            int dredValue = 0, dgreenValue = 0, dblueValue = 0;
            int minred = destination.RoundedRed[0]; ////min to compare with
            int mingreen = destination.RoundedGreen[0];
            int minblue = destination.RoundedBlue[0];
            bool equalRed = false, equalGreen = false, equalBlue = false;
            for (int i = 0; i < 256; i++)
            {
                int j = 0;
                sredValue = source.RoundedRed[i];
                sgreenValue = source.RoundedGreen[i];
                sblueValue = source.RoundedBlue[i];

                minred = Convert.ToInt32(Math.Abs(sredValue - destination.RoundedRed[0]));
                mingreen = Convert.ToInt32(Math.Abs(sgreenValue - destination.RoundedGreen[0]));
                minblue = Convert.ToInt32(Math.Abs(sblueValue - destination.RoundedBlue[0]));

                while (j < 256)
                {
                    dredValue = destination.RoundedRed[j];
                    dgreenValue = destination.RoundedGreen[j];
                    dblueValue = destination.RoundedBlue[j];

                    if (sredValue == dredValue)
                    {
                        equalRed = true;
                        matchRed = j;
                    }

                    if (sgreenValue == dgreenValue)
                    {
                        equalGreen = true;
                        matchGreen = j;
                    }

                    if (sblueValue == dblueValue)
                    {
                        equalBlue = true;
                        matchBlue = j;
                    }
                    else if (sredValue != dredValue && equalRed != true)   
                    {
                        calculation = Convert.ToInt32(Math.Abs(sredValue - dredValue));

                        if (calculation <= minred)
                        {
                            minred = calculation;
                            matchRed = j; ////new matched value 
                        }
                    }
                    else if (sgreenValue != dgreenValue && equalGreen != true)    
                    {
                        calculation = Convert.ToInt32(Math.Abs(sgreenValue - dgreenValue));

                        if (calculation <= mingreen)
                        {
                            mingreen = calculation;
                            ////new matched value 
                            matchGreen = j; 
                        }
                    }
                    else if (sblueValue != dblueValue && equalBlue != true)       
                    {
                        calculation = Convert.ToInt32(Math.Abs(sblueValue - dblueValue));

                        if (calculation <= minblue)
                        {
                            minblue = calculation;
                            matchBlue = j; ////new matched value 
                        }
                    }

                    j++;
                }

               matchedRedArr[i] = matchRed;
                matchedGreenArr[i] = matchGreen;
                matchedBlueArr[i] = matchBlue;
            }

            for (int i = 0; i < image1.ImageHeight; i++)
            {
                for (int j = 0; j < image1.ImageWidth; j++)
                {                   
                    this.buffer[i, j].Red = matchedRedArr[image1.Buffer[i, j].Red];
                    this.buffer[i, j].Green = matchedGreenArr[image1.Buffer[i, j].Green];
                    this.buffer[i, j].Blue = matchedBlueArr[image1.Buffer[i, j].Blue];
                }
            }

            return this.buffer;
        }

        /// <summary>
        /// Add to images of type ReadImage
        /// </summary>
        /// <param name="image1">first image of type ReadImage</param>
        /// <param name="image2">second image of type ReadImage</param>
        /// <param name="fraction">user input between 0 and 1 to specify the participation percentage of each image in the result</param>
        /// <returns>2D buffer </returns>
        public RGBcolor[,]Add_images(ReadImage image1, ReadImage image2, double fraction)
        {
            this.height = image1.ImageHeight;
            this.width = image1.ImageWidth;
           this.buffer = new RGBcolor[this.height, this.width];
            for (int i = 0; i < this.height; i++)
            {
                for (int j = 0; j < this.width; j++)
                {
                   this.buffer[i, j].Red = Convert.ToInt32((image1.Buffer[i, j].Red * fraction) + (image2.Buffer[i, j].Red * (1 - fraction)));
                   this.buffer[i, j].Green = Convert.ToInt32((image1.Buffer[i, j].Green * fraction) + (image2.Buffer[i, j].Green * (1 - fraction)));
                   this.buffer[i, j].Blue = Convert.ToInt32((image1.Buffer[i, j].Blue * fraction) + (image2.Buffer[i, j].Blue * (1 - fraction))); 
                }
            }

            return this.buffer;            
        }

        /// <summary>
        /// Subtract two images 
        /// </summary>
        /// <param name="image1">first image of type ReadImage</param>
        /// <param name="image2">secong image of type ReadImage</param>
        /// <returns>2D buffer</returns>
        public RGBcolor[,] Subtract_images(ReadImage image1, ReadImage image2)
        {
           this.height = image1.ImageHeight;
            this.width = image1.ImageWidth;
           this.buffer = new RGBcolor[this.height, this.width];
           RGBcolor[,] fbuffer = new RGBcolor[this.height, this.width];
           for (int i = 0; i < this.height; i++)
           {
               for (int j = 0; j < this.width; j++)
               {
                   this.buffer[i, j].Red = Math.Abs(image1.Buffer[i, j].Red - image2.Buffer[i, j].Red);
                   this.buffer[i, j].Green = Math.Abs(image1.Buffer[i, j].Green - image2.Buffer[i, j].Green);
                   this.buffer[i, j].Blue = Math.Abs(image1.Buffer[i, j].Blue - image2.Buffer[i, j].Blue);
               }
           }

           int height = this.height;
           int width = this.width;
          int minR = 0;
          int minG = 0;
           int minB = 0;
           int maxR = 255;
          int maxG = 255;
           int maxB = 255;
           for (int i = 0; i < height; i++)
           {
               for (int j = 0; j < width; j++)
               {
                   if (this.buffer[i, j].Red < minR)
                   {
                       minR = this.buffer[i, j].Red;
                   }

                   if (this.buffer[i, j].Red > maxR)
                   {
                       maxR = this.buffer[i, j].Red;
                   }

                   if (this.buffer[i, j].Green < minG)
                   {
                       minG = this.buffer[i, j].Green;
                   }

                   if (this.buffer[i, j].Green > maxG)
                   {
                       maxG = this.buffer[i, j].Green;
                   }

                   if (this.buffer[i, j].Blue < minB)
                   {
                       minB = this.buffer[i, j].Blue;
                   }

                   if (this.buffer[i, j].Blue > maxB)
                   {
                       maxB = this.buffer[i, j].Blue;
                   }
               }
           }

           for (int i = 0; i < height; i++)
           {
               for (int j = 0; j < width; j++)
               {
                  fbuffer[i, j].Red = (int)(((double)this.buffer[i, j].Red - (double)minR) / ((double)maxR - (double)minR)) * 255;
                   fbuffer[i, j].Green = (int)(((double)this.buffer[i, j].Green - (double)minG) / ((double)maxG - (double)minG)) * 255;
                   fbuffer[i, j].Blue = (int)(((double)this.buffer[i, j].Blue - (double)minB) / ((double)maxB - (double)minB)) * 255;
               }
           }

        return fbuffer;
        }

       /// <summary>
       /// Not operation
       /// </summary>
       /// <param name="image">image of type bitmap</param>
       /// <returns>bitmap image</returns>
        public Bitmap Not(Image image)
        {
            Bitmap bm = new Bitmap(Convert.ToInt32(image.Width), Convert.ToInt32(image.Height));
            Bitmap old = new Bitmap(image);
            Color clr, cl;
            int newValR, newValG, newValB;

            for (int i = 0; i < image.Height; i++)
            {
                for (int j = 0; j < image.Width; j++)
                {
                    cl = old.GetPixel(j, i);
                    newValR = 255 - cl.R;
                    newValG = 255 - cl.G;
                    newValB = 255 - cl.B;
                    clr = Color.FromArgb(255, newValR, newValG, newValB);
                    bm.SetPixel(j, i, clr);
                }
            }

            return bm;
        }

        /// <summary>
        /// And operation 
        /// </summary>
        /// <param name="image1">first image</param>
        /// <param name="image2">second image</param>
        /// <returns>bitmap image</returns>
        public Bitmap And(Image image1, Image image2)
        {
            Bitmap bm1 = new Bitmap(image1);
            Bitmap bm2 = new Bitmap(image2);
            Bitmap newImage = new Bitmap(Convert.ToInt32(image1.Width), Convert.ToInt32(image1.Height));
            Color clr1, clr2, final;
            for (int i = 0; i < image1.Height; i++)
            {
                for (int j = 0; j < image1.Width; j++)
                {
                    clr1 = bm1.GetPixel(j, i);
                    clr2 = bm2.GetPixel(j, i);
                    final = Color.FromArgb(255, clr1.R & clr2.R, clr1.G & clr2.G, clr1.B & clr2.B);
                    newImage.SetPixel(j, i, final);
                }
            }

            return newImage;
        }

        /// <summary>
        /// Oring 2 images
        /// </summary>
        /// <param name="image1">first image </param>
        /// <param name="image2">second image</param>
        /// <returns>bitmap image</returns>
        public Bitmap Or(Image image1, Image image2)
        {
            Bitmap bm1 = new Bitmap(image1);
            Bitmap bm2 = new Bitmap(image2);
            Bitmap newImage = new Bitmap(Convert.ToInt32(image1.Width), Convert.ToInt32(image1.Height));
            Color clr1, clr2, final;
            for (int i = 0; i < image1.Height; i++)
            {
                for (int j = 0; j < image1.Width; j++)
                {
                    clr1 = bm1.GetPixel(j, i);
                    clr2 = bm2.GetPixel(j, i);
                    final = Color.FromArgb(255, clr1.R | clr2.R, clr1.G | clr2.G, clr1.B | clr2.B);
                    newImage.SetPixel(j, i, final);
                }
            }

            return newImage;
        }
    }
}
